using System;

using AGG.Transform;
using AGG.Image;
using AGG.VertexSource;
using AGG.UI;
using AGG.RasterizerScanline;

namespace AGG
{
    public class perspective_application : MatchParentBoundsWidget
    {
        AGG.ScanlineRasterizer g_rasterizer = new ScanlineRasterizer();
        ScanlineCachePacked8 g_scanline = new ScanlineCachePacked8();

        UI.PolygonEditWidget quadPolygonControl;
        UI.RadioButtonWidget transformationTypeRadioButton;
        private LionShape lionShape = new LionShape();

        public perspective_application()
        {
            quadPolygonControl = new AGG.UI.PolygonEditWidget(4, 5.0);
            transformationTypeRadioButton = new AGG.UI.RadioButtonWidget(420, 5.0, 420+130.0, 55.0);
            transformationTypeRadioButton.SelectionChanged += new rbox_ctrl_impl.SelectionChangedEventHandler(NeedsRedraw);
            quadPolygonControl.SetXN(0, lionShape.Bounds.x1);
            quadPolygonControl.SetYN(0, lionShape.Bounds.y2);
            quadPolygonControl.SetXN(1, lionShape.Bounds.x2);
            quadPolygonControl.SetYN(1, lionShape.Bounds.y2);
            quadPolygonControl.SetXN(2, lionShape.Bounds.x2);
            quadPolygonControl.SetYN(2, lionShape.Bounds.y1);
            quadPolygonControl.SetXN(3, lionShape.Bounds.x1);
            quadPolygonControl.SetYN(3, lionShape.Bounds.y1);

            transformationTypeRadioButton.add_item("Bilinear");
            transformationTypeRadioButton.add_item("Perspective");
            transformationTypeRadioButton.cur_item(0);
            AddChild(transformationTypeRadioButton);
        }

        void NeedsRedraw(object sender, MouseEventArgs mouseEvent)
        {
            Invalidate();
        }

        public void OnInitialize()
        {
            double dx = Width / 2.0 - (quadPolygonControl.GetXN(1) - quadPolygonControl.GetXN(0)) / 2.0;
            double dy = Height / 2.0 - (quadPolygonControl.GetYN(0) - quadPolygonControl.GetYN(2)) / 2.0;
            quadPolygonControl.AddXN(0, dx);
            quadPolygonControl.AddYN(0, dy);
            quadPolygonControl.AddXN(1, dx);
            quadPolygonControl.AddYN(1, dy);
            quadPolygonControl.AddXN(2, dx);
            quadPolygonControl.AddYN(2, dy);
            quadPolygonControl.AddXN(3, dx);
            quadPolygonControl.AddYN(3, dy);
        }

        bool didInit = false;
        public override void OnDraw(Graphics2D graphics2D)
        {
            if (!didInit)
            {
                didInit = true;
                OnInitialize();
            }
            ImageBuffer image;
            if (graphics2D.DestImage.BitDepth == 32)
            {
                image = new ImageBuffer();
                image.Attach(graphics2D.DestImage, new BlenderBGRA());
            }
            else
            {
                if (graphics2D.DestImage.BitDepth != 24)
                {
                    throw new System.NotSupportedException();
                }
                image = new ImageBuffer();
                image.Attach(graphics2D.DestImage, new BlenderBGR());
            }
            ImageClippingProxy clippingProxy = new ImageClippingProxy(image);
            clippingProxy.clear(new RGBA_Doubles(1, 1, 1));

            g_rasterizer.SetVectorClipBox(0, 0, Width, Height);

            if(transformationTypeRadioButton.cur_item() == 0)
            {
                Bilinear tr = new Bilinear(lionShape.Bounds.x1, lionShape.Bounds.y1, lionShape.Bounds.x2, lionShape.Bounds.y2, quadPolygonControl.polygon());
                if(tr.is_valid())
                {
                    //--------------------------
                    // Render transformed lion
                    //
                    VertexSourceApplyTransform trans = new VertexSourceApplyTransform(lionShape.Path, tr);

                    agg_renderer_scanline.Default.RenderSolidAllPaths(clippingProxy, g_rasterizer, g_scanline, trans, lionShape.Colors, lionShape.PathIndex, lionShape.NumPaths);
                    //--------------------------



                    //--------------------------
                    // Render transformed ellipse
                    //
                    VertexSource.Ellipse ell = new AGG.VertexSource.Ellipse((lionShape.Bounds.x1 + lionShape.Bounds.x2) * 0.5, (lionShape.Bounds.y1 + lionShape.Bounds.y2) * 0.5,
                                     (lionShape.Bounds.x2 - lionShape.Bounds.x1) * 0.5, (lionShape.Bounds.y2 - lionShape.Bounds.y1) * 0.5,
                                     200);
                    conv_stroke ell_stroke = new conv_stroke(ell);
                    ell_stroke.width(3.0);
                    VertexSourceApplyTransform trans_ell = new VertexSourceApplyTransform(ell, tr);

                    VertexSourceApplyTransform trans_ell_stroke = new VertexSourceApplyTransform(ell_stroke, tr);

                    g_rasterizer.add_path(trans_ell);
                    agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxy, g_rasterizer, g_scanline, new RGBA_Bytes(0.5, 0.3, 0.0, 0.3));

                    g_rasterizer.add_path(trans_ell_stroke);
                    agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxy, g_rasterizer, g_scanline, new RGBA_Bytes(0.0, 0.3, 0.2, 1.0));
                }
            }
            else
            {
                Perspective tr = new Perspective(lionShape.Bounds.x1, lionShape.Bounds.y1, lionShape.Bounds.x2, lionShape.Bounds.y2, quadPolygonControl.polygon());
                if(tr.is_valid())
                {
                    // Render transformed lion
                    VertexSourceApplyTransform trans = new VertexSourceApplyTransform(lionShape.Path, tr);

                    agg_renderer_scanline.Default.RenderSolidAllPaths(clippingProxy, g_rasterizer, g_scanline, trans, lionShape.Colors, lionShape.PathIndex, lionShape.NumPaths);

                    // Render transformed ellipse
                    VertexSource.Ellipse FilledEllipse = new AGG.VertexSource.Ellipse((lionShape.Bounds.x1 + lionShape.Bounds.x2) * 0.5, (lionShape.Bounds.y1 + lionShape.Bounds.y2) * 0.5,
                                     (lionShape.Bounds.x2 - lionShape.Bounds.x1) * 0.5, (lionShape.Bounds.y2 - lionShape.Bounds.y1) * 0.5,
                                     200);

                    conv_stroke EllipseOutline = new conv_stroke(FilledEllipse);
                    EllipseOutline.width(3.0);
                    VertexSourceApplyTransform TransformedFilledEllipse = new VertexSourceApplyTransform(FilledEllipse, tr);

                    VertexSourceApplyTransform TransformedEllipesOutline = new VertexSourceApplyTransform(EllipseOutline, tr);

                    g_rasterizer.add_path(TransformedFilledEllipse);
                    agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxy, g_rasterizer, g_scanline, new RGBA_Bytes(0.5, 0.3, 0.0, 0.3));

                    g_rasterizer.add_path(TransformedEllipesOutline);
                    agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxy, g_rasterizer, g_scanline, new RGBA_Bytes(0.0, 0.3, 0.2, 1.0));
                }
            }

            //--------------------------
            // Render the "quad" tool and controls
            g_rasterizer.add_path(quadPolygonControl);
            agg_renderer_scanline.Default.render_scanlines_aa_solid(clippingProxy, g_rasterizer, g_scanline, new RGBA_Bytes(0, 0.3, 0.5, 0.6));
            //m_trans_type.Render(g_rasterizer, g_scanline, clippingProxy);
            base.OnDraw(graphics2D);
        }

        public override void OnMouseDown(MouseEventArgs mouseEvent)
        {
            if (mouseEvent.Button == MouseButtons.Left)
            {
            	quadPolygonControl.OnMouseDown(mouseEvent);
                if (MouseCaptured)
                {
                    Invalidate();
                }
            }
            
            base.OnMouseDown(mouseEvent);
        }

        public override void OnMouseMove(MouseEventArgs mouseEvent)
        {
            if (mouseEvent.Button == MouseButtons.Left)
            {
            	quadPolygonControl.OnMouseMove(mouseEvent);
                if (MouseCaptured)
                {
                    Invalidate();
                }
            }

            base.OnMouseMove(mouseEvent);
        }

        public override void OnMouseUp(MouseEventArgs mouseEvent)
        {
        	quadPolygonControl.OnMouseUp(mouseEvent);
            if (MouseCaptured)
            {
                Invalidate();
            }

            base.OnMouseUp(mouseEvent);
        }

        public static void StartDemo()
        {
            GuiHalFactory.SetGuiBackend(GuiHalFactory.KnownGuiFactoriesIndexes.WindowsFormsBitmap);
            GuiHalSurface primaryWindow = GuiHalFactory.CreatePrimarySurface(600, 600, GuiHalSurface.CreateFlags.Resizable, GuiHalSurface.PixelFormat.PixelFormatBgr24);

            primaryWindow.Caption = "AGG Example. Perspective Transformations";

            primaryWindow.AddChild(new perspective_application());
            primaryWindow.Run();
        }

        [STAThread]
        public static void Main(string[] args)
        {
        	StartDemo();
        }
    }
};

